﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

using SharpObjects.Configuration;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.Instantiation;
using SharpObjects.Interfaces;
using SharpObjects.PathMapping;
using SharpObjects.RuleEngine;
using SharpObjects.RuleEngine.DataProviders;
using SharpObjects.Utils;


namespace SharpRuleEngineTest
{


    class SharpRuleEngineTest
    {
        static void Main(string[] args)
        {
            ViewNavigatorTest();
            CarProcessorTest();
        }

        static void ViewNavigatorTest()
        {
            string viewsFile = "views.xml";
            string dataFile = "ViewNavigatorTestData.xml";

            IConfigurationProvider viewsProvider = new XmlConfigurationProvider(viewsFile, new WebServicePathMapper());
            IConfigurationProvider dataConfig = new XmlConfigurationProvider(dataFile, new WebServicePathMapper());

            ITypeDescriptor xmlDataProviderTypeDescriptor = new TypeDescriptor()
            {
                AssemblyPath = "SharpObjects.RuleEngine",
                TypeName = "SharpObjects.RuleEngine.DataProviders.XmlDataProvider"
            };

            IDataProvider dataProvider = dataConfig.GetObject<IDataProvider>("/*", xmlDataProviderTypeDescriptor);

            ITypeDescriptor viewTypeDescriptor = new TypeDescriptor()
            {
                AssemblyPath = "SharpRuleEngineTest.exe",
                TypeName = "SharpRuleEngineTest.ViewDescriptor"
            };

            IRuleEngine ruleEngine = new RuleEngine();
            ViewDescriptor[] views = viewsProvider.GetObjects<ViewDescriptor>("/*/view", viewTypeDescriptor);

            IRuleEngineContext context = new RuleEngineContext();

            ViewDescriptor currentView = views[0];
            string userInput;

            // TEST 1 - FIRST TIME USER
            Console.WriteLine("--------------\nTest 1 - first time user");
            context.SetValue<bool>("first_time_user", true);

            Console.WriteLine("Current view: {0}", currentView.Id);
            Console.Write("Enter 'n' for next view or 'q' to quit: ");

            while((userInput = Console.ReadLine()) == "n")
            {
                string uiEventId = "next";

                UiEvent uiEvent = currentView.FindEvent(uiEventId);

                if(uiEvent == null)
                {
                    Console.WriteLine("No UI event handlers for the {0} event found in the current view ({1})", uiEventId, currentView.Id);
                }
                else
                {
                    // execute navigation rules
                    ruleEngine.Execute(ref context, dataProvider, uiEvent.NavigationRules.ToArray());

                    string nextViewId = context.GetValue<string>("next_view", null);

                    if(currentView.Id == nextViewId)
                    {
                        Console.WriteLine("Staying on the same view");
                    }
                    else
                    {
                        Console.WriteLine("Navigating to: {0}", nextViewId);

                        ViewDescriptor nextViewDescriptor = FindViewDescriptor(nextViewId, views);

                        if(nextViewDescriptor != null)
                        {
                            currentView = nextViewDescriptor;
                        }
                        else
                        {
                            Console.WriteLine("ERROR: View descriptor {0} not found", nextViewDescriptor);
                        }
                    }
                }

                Console.WriteLine("Current view: {0}", currentView.Id);
                Console.Write("Enter 'n' for next view or 'q' to quit: ");
            }

            // TEST 2 - RETURNING USER
            currentView = views[0];
            Console.WriteLine("--------------\nTest 2 - returning user");
            context.SetValue<bool>("first_time_user", false);

            Console.WriteLine("Current view: {0}", currentView.Id);
            Console.Write("Enter 'n' for next view or 'q' to quit: ");

            while ((userInput = Console.ReadLine()) == "n")
            {
                string uiEventId = "next";

                UiEvent uiEvent = currentView.FindEvent(uiEventId);

                if (uiEvent == null)
                {
                    Console.WriteLine("No UI event handlers for the {0} event found in the current view ({1})", uiEventId, currentView.Id);
                }
                else
                {
                    // execute navigation rules
                    ruleEngine.Execute(ref context, dataProvider, uiEvent.NavigationRules.ToArray());

                    string nextViewId = context.GetValue<string>("next_view", null);

                    if (currentView.Id == nextViewId)
                    {
                        Console.WriteLine("Staying on the same view");
                    }
                    else
                    {
                        Console.WriteLine("Navigating to: {0}", nextViewId);

                        ViewDescriptor nextViewDescriptor = FindViewDescriptor(nextViewId, views);

                        if (nextViewDescriptor != null)
                        {
                            currentView = nextViewDescriptor;
                        }
                        else
                        {
                            Console.WriteLine("ERROR: View descriptor {0} not found", nextViewDescriptor);
                        }
                    }
                }

                Console.WriteLine("Current view: {0}", currentView.Id);
                Console.Write("Enter 'n' for next view or 'q' to quit: ");
            }
        }

        static ViewDescriptor FindViewDescriptor(string id, ViewDescriptor[] viewDescriptors)
        {
            foreach (ViewDescriptor viewDescriptor in viewDescriptors)
            {
                if(viewDescriptor.Id == id)
                {
                    return viewDescriptor;
                }
            }

            return null;
        }

        static void CarProcessorTest()
        {
            string inputFile = "InputFile.xml";
            string outputFile = "output.csv";

            if (File.Exists(outputFile))
            {
                File.Delete(outputFile);
            }

            IConfigurationProvider settings = new XmlConfigurationProvider("settings.config", new WebServicePathMapper());

            IConfigurationReader input = new XmlConfigurationProvider(inputFile, new WebServicePathMapper());
            ITypeDescriptor xmlDataProviderTypeDescriptor = new TypeDescriptor()
                                                 {
                                                     AssemblyPath = "SharpObjects.RuleEngine",
                                                     TypeName = "SharpObjects.RuleEngine.DataProviders.XmlDataProvider"
                                                 };

            IDataProvider[] inputProviders = input.GetObjects<IDataProvider>("//car", xmlDataProviderTypeDescriptor);

            IRule[] rules = settings.GetObjects<IRule>("//rules/*");
            IRuleEngine ruleEngine = new RuleEngine();
            
            foreach (IDataProvider inputProvider in inputProviders)
            {
                IRuleEngineContext context = new RuleEngineContext();
                context.SetValue("output_file", outputFile);

                ruleEngine.Execute(ref context, inputProvider, rules);
            }

        }
    }
}

    